// Copyright (c) 2021, gottingen group.
// All rights reserved.
// Created by liyinbin lijippy@163.com
//

#include "abel/strings/internal/charconv_parse.h"

#include <cassert>
#include <cstdint>
#include <limits>
#include "abel/strings/char_conv.h"
#include "abel/strings/internal/char_traits.h"

namespace abel {

namespace {

// ParseFloat<10> will read the first 19 significant digits of the mantissa.
// This number was chosen for multiple reasons.
//
// (a) First, for whatever integer type we choose to represent the mantissa, we
// want to choose the largest possible number of decimal digits for that integer
// type.  We are using uint64_t, which can express any 19-digit unsigned
// integer.
//
// (b) Second, we need to parse enough digits that the binary value of any
// mantissa we capture has more bits of resolution than the mantissa
// representation in the target float.  Our algorithm requires at least 3 bits
// of headway, but 19 decimal digits give a little more than that.
//
// The following static assertions verify the above comments:
constexpr int kDecimalMantissaDigitsMax = 19;

static_assert(std::numeric_limits<uint64_t>::digits10 ==
              kDecimalMantissaDigitsMax,
              "(a) above");

// IEEE doubles, which we assume in abel, have 53 binary bits of mantissa.
static_assert(std::numeric_limits<double>::is_iec559, "IEEE double assumed");
static_assert(std::numeric_limits<double>::radix == 2, "IEEE double fact");
static_assert(std::numeric_limits<double>::digits == 53, "IEEE double fact");

// The lowest valued 19-digit decimal mantissa we can read still contains
// sufficient information to reconstruct a binary mantissa.
static_assert(1000000000000000000u > (uint64_t(1) << (53 + 3)), "(b) above");

// ParseFloat<16> will read the first 15 significant digits of the mantissa.
//
// Because a base-16-to-base-2 conversion can be done exactly, we do not need
// to maximize the number of scanned hex digits to improve our conversion.  What
// is required is to scan two more bits than the mantissa can represent, so that
// we always round correctly.
//
// (One extra bit does not suffice to perform correct rounding, since a number
// exactly halfway between two representable floats has unique rounding rules,
// so we need to differentiate between a "halfway between" number and a "closer
// to the larger value" number.)
constexpr int kHexadecimalMantissaDigitsMax = 15;

// The minimum number of significant bits that will be read from
// kHexadecimalMantissaDigitsMax hex digits.  We must subtract by three, since
// the most significant digit can be a "1", which only contributes a single
// significant bit.
constexpr int kGuaranteedHexadecimalMantissaBitPrecision =
        4 * kHexadecimalMantissaDigitsMax - 3;

static_assert(kGuaranteedHexadecimalMantissaBitPrecision >
              std::numeric_limits<double>::digits + 2,
              "kHexadecimalMantissaDigitsMax too small");

// We also impose a limit on the number of significant digits we will read from
// an exponent, to avoid having to deal with integer overflow.  We use 9 for
// this purpose.
//
// If we read a 9 digit exponent, the end result of the conversion will
// necessarily be infinity or zero, depending on the sign of the exponent.
// Therefore we can just drop extra digits on the floor without any extra
// logic.
constexpr int kDecimalExponentDigitsMax = 9;
static_assert(std::numeric_limits<int>::digits10 >= kDecimalExponentDigitsMax,
              "int type too small");

// To avoid incredibly large inputs causing integer overflow for our exponent,
// we impose an arbitrary but very large limit on the number of significant
// digits we will accept.  The implementation refuses to match a string with
// more consecutive significant mantissa digits than this.
constexpr int kDecimalDigitLimit = 50000000;

// Corresponding limit for hexadecimal digit inputs.  This is one fourth the
// amount of kDecimalDigitLimit, since each dropped hexadecimal digit requires
// a binary exponent adjustment of 4.
constexpr int kHexadecimalDigitLimit = kDecimalDigitLimit / 4;

// The largest exponent we can read is 999999999 (per
// kDecimalExponentDigitsMax), and the largest exponent adjustment we can get
// from dropped mantissa digits is 2 * kDecimalDigitLimit, and the sum of these
// comfortably fits in an integer.
//
// We count kDecimalDigitLimit twice because there are independent limits for
// numbers before and after the decimal point.  (In the case where there are no
// significant digits before the decimal point, there are independent limits for
// post-decimal-point leading zeroes and for significant digits.)
static_assert(999999999 + 2 * kDecimalDigitLimit <
              std::numeric_limits<int>::max(),
              "int type too small");
static_assert(999999999 + 2 * (4 * kHexadecimalDigitLimit) <
              std::numeric_limits<int>::max(),
              "int type too small");

// Returns true if the provided bitfield allows parsing an exponent value
// (e.g., "1.5e100").
bool AllowExponent(chars_format flags) {
    bool fixed = (flags & chars_format::fixed) == chars_format::fixed;
    bool scientific =
            (flags & chars_format::scientific) == chars_format::scientific;
    return scientific || !fixed;
}

// Returns true if the provided bitfield requires an exponent value be present.
bool RequireExponent(chars_format flags) {
    bool fixed = (flags & chars_format::fixed) == chars_format::fixed;
    bool scientific =
            (flags & chars_format::scientific) == chars_format::scientific;
    return scientific && !fixed;
}

const int8_t kAsciiToInt[256] = {
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
        9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1};

// Returns true if `ch` is a digit in the given base
template<int base>
bool IsDigit(char ch);

// Converts a valid `ch` to its digit value in the given base.
template<int base>
unsigned ToDigit(char ch);

// Returns true if `ch` is the exponent delimiter for the given base.
template<int base>
bool IsExponentCharacter(char ch);

// Returns the maximum number of significant digits we will read for a float
// in the given base.
template<int base>
constexpr int MantissaDigitsMax();

// Returns the largest consecutive run of digits we will accept when parsing a
// number in the given base.
template<int base>
constexpr int DigitLimit();

// Returns the amount the exponent must be adjusted by for each dropped digit.
// (For decimal this is 1, since the digits are in base 10 and the exponent base
// is also 10, but for hexadecimal this is 4, since the digits are base 16 but
// the exponent base is 2.)
template<int base>
constexpr int DigitMagnitude();

template<>
bool IsDigit<10>(char ch) {
    return ch >= '0' && ch <= '9';
}

template<>
bool IsDigit<16>(char ch) {
    return kAsciiToInt[static_cast<unsigned char>(ch)] >= 0;
}

template<>
unsigned ToDigit<10>(char ch) {
    return ch - '0';
}

template<>
unsigned ToDigit<16>(char ch) {
    return kAsciiToInt[static_cast<unsigned char>(ch)];
}

template<>
bool IsExponentCharacter<10>(char ch) {
    return ch == 'e' || ch == 'E';
}

template<>
bool IsExponentCharacter<16>(char ch) {
    return ch == 'p' || ch == 'P';
}

template<>
constexpr int MantissaDigitsMax<10>() {
    return kDecimalMantissaDigitsMax;
}

template<>
constexpr int MantissaDigitsMax<16>() {
    return kHexadecimalMantissaDigitsMax;
}

template<>
constexpr int DigitLimit<10>() {
    return kDecimalDigitLimit;
}

template<>
constexpr int DigitLimit<16>() {
    return kHexadecimalDigitLimit;
}

template<>
constexpr int DigitMagnitude<10>() {
    return 1;
}

template<>
constexpr int DigitMagnitude<16>() {
    return 4;
}

// Reads decimal digits from [begin, end) into *out.  Returns the number of
// digits consumed.
//
// After max_digits has been read, keeps consuming characters, but no longer
// adjusts *out.  If a nonzero digit is dropped this way, *dropped_nonzero_digit
// is set; otherwise, it is left unmodified.
//
// If no digits are matched, returns 0 and leaves *out unchanged.
//
// ConsumeDigits does not protect against overflow on *out; max_digits must
// be chosen with respect to type T to avoid the possibility of overflow.
template<int base, typename T>
std::size_t ConsumeDigits(const char *begin, const char *end, int max_digits,
                          T *out, bool *dropped_nonzero_digit) {
    if (base == 10) {
        assert(max_digits <= std::numeric_limits<T>::digits10);
    } else if (base == 16) {
        assert(max_digits * 4 <= std::numeric_limits<T>::digits);
    }
    const char *const original_begin = begin;

    // Skip leading zeros, but only if *out is zero.
    // They don't cause an overflow so we don't have to count them for
    // `max_digits`.
    while (!*out && end != begin && *begin == '0') ++begin;

    T accumulator = *out;
    const char *significant_digits_end =
            (end - begin > max_digits) ? begin + max_digits : end;
    while (begin < significant_digits_end && IsDigit<base>(*begin)) {
        // Do not guard against *out overflow; max_digits was chosen to avoid this.
        // Do assert against it, to detect problems in debug builds.
        auto digit = static_cast<T>(ToDigit<base>(*begin));
        assert(accumulator * base >= accumulator);
        accumulator *= base;
        assert(accumulator + digit >= accumulator);
        accumulator += digit;
        ++begin;
    }
    bool dropped_nonzero = false;
    while (begin < end && IsDigit<base>(*begin)) {
        dropped_nonzero = dropped_nonzero || (*begin != '0');
        ++begin;
    }
    if (dropped_nonzero && dropped_nonzero_digit != nullptr) {
        *dropped_nonzero_digit = true;
    }
    *out = accumulator;
    return begin - original_begin;
}

// Returns true if `v` is one of the chars allowed inside parentheses following
// a NaN.
bool IsNanChar(char v) {
    return (v == '_') || (v >= '0' && v <= '9') || (v >= 'a' && v <= 'z') ||
           (v >= 'A' && v <= 'Z');
}

// Checks the range [begin, end) for a strtod()-formatted infinity or NaN.  If
// one is found, sets `out` appropriately and returns true.
bool ParseInfinityOrNan(const char *begin, const char *end,
                        strings_internal::ParsedFloat *out) {
    if (end - begin < 3) {
        return false;
    }
    switch (*begin) {
        case 'i':
        case 'I': {
            // An infinity std::string consists of the characters "inf" or "infinity",
            // case insensitive.
            if (strings_internal::char_case_cmp(begin + 1, "nf", 2) != 0) {
                return false;
            }
            out->type = strings_internal::FloatType::kInfinity;
            if (end - begin >= 8 &&
                strings_internal::char_case_cmp(begin + 3, "inity", 5) == 0) {
                out->end = begin + 8;
            } else {
                out->end = begin + 3;
            }
            return true;
        }
        case 'n':
        case 'N': {
            // A NaN consists of the characters "nan", case insensitive, optionally
            // followed by a parenthesized sequence of zero or more alphanumeric
            // characters and/or underscores.
            if (strings_internal::char_case_cmp(begin + 1, "an", 2) != 0) {
                return false;
            }
            out->type = strings_internal::FloatType::kNan;
            out->end = begin + 3;
            // NaN is allowed to be followed by a parenthesized std::string, consisting of
            // only the characters [a-zA-Z0-9_].  Match that if it's present.
            begin += 3;
            if (begin < end && *begin == '(') {
                const char *nan_begin = begin + 1;
                while (nan_begin < end && IsNanChar(*nan_begin)) {
                    ++nan_begin;
                }
                if (nan_begin < end && *nan_begin == ')') {
                    // We found an extra NaN specifier range
                    out->subrange_begin = begin + 1;
                    out->subrange_end = nan_begin;
                    out->end = nan_begin + 1;
                }
            }
            return true;
        }
        default:
            return false;
    }
}
}  // namespace

namespace strings_internal {

template<int base>
strings_internal::ParsedFloat ParseFloat(const char *begin, const char *end,
                                         chars_format format_flags) {
    strings_internal::ParsedFloat result;

    // Exit early if we're given an empty range.
    if (begin == end) return result;

    // Handle the infinity and NaN cases.
    if (ParseInfinityOrNan(begin, end, &result)) {
        return result;
    }

    const char *const mantissa_begin = begin;
    while (begin < end && *begin == '0') {
        ++begin;  // skip leading zeros
    }
    uint64_t mantissa = 0;

    int exponent_adjustment = 0;
    bool mantissa_is_inexact = false;
    std::size_t pre_decimal_digits = ConsumeDigits<base>(
            begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
    begin += pre_decimal_digits;
    int digits_left;
    if (pre_decimal_digits >= DigitLimit<base>()) {
        // refuse to parse pathological inputs
        return result;
    } else if (pre_decimal_digits > MantissaDigitsMax<base>()) {
        // We dropped some non-fraction digits on the floor.  Adjust our exponent
        // to compensate.
        exponent_adjustment =
                static_cast<int>(pre_decimal_digits - MantissaDigitsMax<base>());
        digits_left = 0;
    } else {
        digits_left =
                static_cast<int>(MantissaDigitsMax<base>() - pre_decimal_digits);
    }
    if (begin < end && *begin == '.') {
        ++begin;
        if (mantissa == 0) {
            // If we haven't seen any nonzero digits yet, keep skipping zeros.  We
            // have to adjust the exponent to reflect the changed place value.
            const char *begin_zeros = begin;
            while (begin < end && *begin == '0') {
                ++begin;
            }
            std::size_t zeros_skipped = begin - begin_zeros;
            if (zeros_skipped >= DigitLimit<base>()) {
                // refuse to parse pathological inputs
                return result;
            }
            exponent_adjustment -= static_cast<int>(zeros_skipped);
        }
        std::size_t post_decimal_digits = ConsumeDigits<base>(
                begin, end, digits_left, &mantissa, &mantissa_is_inexact);
        begin += post_decimal_digits;

        // Since `mantissa` is an integer, each significant digit we read after
        // the decimal point requires an adjustment to the exponent. "1.23e0" will
        // be stored as `mantissa` == 123 and `exponent` == -2 (that is,
        // "123e-2").
        if (post_decimal_digits >= DigitLimit<base>()) {
            // refuse to parse pathological inputs
            return result;
        } else if (post_decimal_digits > static_cast<size_t>(digits_left)) {
            exponent_adjustment -= digits_left;
        } else {
            exponent_adjustment -= post_decimal_digits;
        }
    }
    // If we've found no mantissa whatsoever, this isn't a number.
    if (mantissa_begin == begin) {
        return result;
    }
    // A bare "." doesn't count as a mantissa either.
    if (begin - mantissa_begin == 1 && *mantissa_begin == '.') {
        return result;
    }

    if (mantissa_is_inexact) {
        // We dropped significant digits on the floor.  Handle this appropriately.
        if (base == 10) {
            // If we truncated significant decimal digits, store the full range of the
            // mantissa for future big integer math for exact rounding.
            result.subrange_begin = mantissa_begin;
            result.subrange_end = begin;
        } else if (base == 16) {
            // If we truncated hex digits, reflect this fact by setting the low
            // ("sticky") bit.  This allows for correct rounding in all cases.
            mantissa |= 1;
        }
    }
    result.mantissa = mantissa;

    const char *const exponent_begin = begin;
    result.literal_exponent = 0;
    bool found_exponent = false;
    if (AllowExponent(format_flags) && begin < end &&
        IsExponentCharacter<base>(*begin)) {
        bool negative_exponent = false;
        ++begin;
        if (begin < end && *begin == '-') {
            negative_exponent = true;
            ++begin;
        } else if (begin < end && *begin == '+') {
            ++begin;
        }
        const char *const exponent_digits_begin = begin;
        // Exponent is always expressed in decimal, even for hexadecimal floats.
        begin += ConsumeDigits<10>(begin, end, kDecimalExponentDigitsMax,
                                   &result.literal_exponent, nullptr);
        if (begin == exponent_digits_begin) {
            // there were no digits where we expected an exponent.  We failed to read
            // an exponent and should not consume the 'e' after all.  Rewind 'begin'.
            found_exponent = false;
            begin = exponent_begin;
        } else {
            found_exponent = true;
            if (negative_exponent) {
                result.literal_exponent = -result.literal_exponent;
            }
        }
    }

    if (!found_exponent && RequireExponent(format_flags)) {
        // Provided flags required an exponent, but none was found.  This results
        // in a failure to scan.
        return result;
    }

    // Success!
    result.type = strings_internal::FloatType::kNumber;
    if (result.mantissa > 0) {
        result.exponent = result.literal_exponent +
                          (DigitMagnitude<base>() * exponent_adjustment);
    } else {
        result.exponent = 0;
    }
    result.end = begin;
    return result;
}

template ParsedFloat ParseFloat<10>(const char *begin, const char *end,
                                    chars_format format_flags);

template ParsedFloat ParseFloat<16>(const char *begin, const char *end,
                                    chars_format format_flags);

}  // namespace strings_internal

}  // namespace abel
